package jia.temp;

import jia.core.Compass;
import jia.core.EntryPoint;
import jia.core.Module;
import jia.core.Space;
import jia.core.Wall;
import jia.game.GenericFlags;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.EmptyStackException;
import java.util.List;
import java.util.Stack;

//====================================================

/**
 * @author Alec Lanter
 */
public class MazeModule extends Module {
    
    public static final int START_SPACE_FLAG = 524288;
    public static final int END_SPACE_FLAG = 16777216;
    public static final int SPACE_IS_VISITED = 33554432;
    private static int WIDTH = 10;
    private static int HEIGHT = 10;
    private static final Logger log = Logger.getLogger(MazeModule.class);
    
    //====================================================
    /**
     */
    public MazeModule() {
        super("MAZE", WIDTH, HEIGHT);
        initModule();
    }
    
    //====================================================
    /**
     */
    private void initModule() {
        if (GenericFlags.debugMessages) {
            log.debug("Building a " + width + "x" + height + " maze");
        }
        Stack<int[]> cellStack = new Stack<int[]>();
        String wallImage = "images/walls/stoneWall01.png";
        String[] floorImages = {"images/backdrops/stoneFloor01.png", "images/backdrops/stoneFloor02.png"};
        String doorImage = "images/walls/stoneDoor01.png";
        String parser = "jia.core.graphics.FirstPersonWallImageParser";
        
        // Populate all our spaces with all four walls
        for (int x = 0; x < width; x++) {
            int floorImg = x % 2;
            for (int y = 0; y < height; y++) {
                Space me = new Space();
                me.addWall(new Wall(wallImage, parser, Compass.NORTH));
                me.addWall(new Wall(wallImage, parser, Compass.EAST));
                if (x == width - 1 && y == height - 1) {
                    me.addWall(new Wall(doorImage, parser, Compass.SOUTH));
                } else {
                    me.addWall(new Wall(wallImage, parser, Compass.SOUTH));
                }
                me.addWall(new Wall(wallImage, parser, Compass.WEST));
                me.setBackdropImageName(floorImages[floorImg]);
                setSpace(x, y, me);
                floorImg++;
                floorImg %= 2;
            }
        }
        
        int visitedCells = 1;
        int totalCells = spaces.length - 1;
        int x = (int) (Math.random() * width);
        int y = (int) (Math.random() * height);
        if (GenericFlags.debugMessages) {
            log.debug("Staring at " + x + ", " + y);
        }
        
        Space currentSpace = getSpace(x, y);
        currentSpace.getFlags().setFlag(SPACE_IS_VISITED);
        
        while (visitedCells < totalCells) {
            int[] neighbor = findUnmolestedNeighbor(x, y);
            if (neighbor != null) {
                int nx = neighbor[0];
                int ny = neighbor[1];
                if (GenericFlags.debugMessages) {
                    log.debug("Moving to " + nx + ", " + ny);
                }
                Space nSpace = getSpace(nx, ny);
                nSpace.getFlags().setFlag(SPACE_IS_VISITED);
                if (nx < x) {
                    currentSpace.removeWall(currentSpace.getWall(Compass.WEST));
                    nSpace.removeWall(nSpace.getWall(Compass.EAST));
                } else if (nx > x) {
                    currentSpace.removeWall(currentSpace.getWall(Compass.EAST));
                    nSpace.removeWall(nSpace.getWall(Compass.WEST));
                } else if (ny < y) {
                    currentSpace.removeWall(currentSpace.getWall(Compass.NORTH));
                    nSpace.removeWall(nSpace.getWall(Compass.SOUTH));
                } else if (ny > y) {
                    currentSpace.removeWall(currentSpace.getWall(Compass.SOUTH));
                    nSpace.removeWall(nSpace.getWall(Compass.NORTH));
                }
                
                visitedCells++;
                cellStack.push(new int[]{x, y});
                currentSpace = nSpace;
                x = nx;
                y = ny;
                if (GenericFlags.debugMessages) {
                    log.debug("That's " + visitedCells + " of " + (spaces.length - 1));
                    log.debug("Backtrack has " + cellStack.size() + " entries.");
                }
            } else {
                if (GenericFlags.debugMessages) {
                    log.debug("Trying to backtrack...");
                }
                try {
                    int[] oldPos = cellStack.pop();
                    x = oldPos[0];
                    y = oldPos[1];
                    currentSpace = getSpace(x, y);
                    if (GenericFlags.debugMessages) {
                        log.debug("Backtracking to " + x + ", " + y);
                    }
                } catch (EmptyStackException e) {
                    if (GenericFlags.errorMessages){
                    log.error("Ran out of backtrack spaces before I ran out of maze!");
                    }
                    throw new ExceptionInInitializerError(e);
                }
            }
        }
        
        getSpace(0, 0).getFlags().setFlag(START_SPACE_FLAG);
        getSpace(width - 1, height - 1).getFlags().setFlag(END_SPACE_FLAG);
        EntryPoint ep = new EntryPoint();
        ep.setEntryFacing(Compass.EAST);
        ep.setEntryPosition(0, 0);
        addEntryPoint(ep);
        
        for (int xx = 0; xx < spaces.length; xx++) {
            if (GenericFlags.debugMessages) {
                log.debug("Space #" + xx + ": " + spaces[xx]);
            }
        }
    }
    
    //====================================================
    /**
     * @param x
     * @param y
     * @return
     */
    private int[] findUnmolestedNeighbor(int x, int y) {
        List<int[]> spaceList = new ArrayList<int[]>();
        Space north = getSpace(x, y - 1);
        Space south = getSpace(x, y + 1);
        Space east = getSpace(x + 1, y);
        Space west = getSpace(x - 1, y);
        
        if (north != null && !north.getFlags().hasFlag(SPACE_IS_VISITED)) {
            if (GenericFlags.debugMessages) {
                log.debug("Good neighbor " + x + ", " + (y - 1));
            }
            spaceList.add(new int[]{x, y - 1});
        }
        if (south != null && !south.getFlags().hasFlag(SPACE_IS_VISITED)) {
            if (GenericFlags.debugMessages) {
                log.debug("Good neighbor " + x + ", " + (y + 1));
            }
            spaceList.add(new int[]{x, y + 1});
        }
        if (east != null && !east.getFlags().hasFlag(SPACE_IS_VISITED)) {
            if (GenericFlags.debugMessages) {
                log.debug("Good neighbor " + (x + 1) + ", " + y);
            }
            spaceList.add(new int[]{x + 1, y});
        }
        if (west != null && !west.getFlags().hasFlag(SPACE_IS_VISITED)) {
            if (GenericFlags.debugMessages) {
                log.debug("Good neighbor " + (x - 1) + ", " + y);
            }
            spaceList.add(new int[]{x - 1, y});
        }
        if (GenericFlags.debugMessages) {
            log.debug("Found " + spaceList.size() + " potential neighbors.");
        }
        
        if (spaceList.size() == 0) {
            return null;
        } else {
            return spaceList.get((int) (Math.random() * spaceList.size()));
        }
    }
}
